package pl;

import javacard.framework.Util;
import javacard.security.KeyBuilder;
import javacard.security.RSAPrivateKey;
import javacard.security.RSAPublicKey;

public class KeyContainer {

	RSAPublicKey publicKey;
	RSAPrivateKey privateKey;

	private byte keyId;
	public byte[] userCertificate;
	public short userCertLen;
	
	public byte[] certificateId;
	public short certificateIdLen;
	
	private short privateKeyExponentLength;
	private byte[] privateKeyExponent;
	
	public short keySeedLength;
	private short keySeedLengthImport; 
	
	byte[] keySeed;
	private short modulusLength;
	public byte[] modulus;
	private short publicKeyExponentLength;
	private byte[] publicKeyExponent;
	public boolean isCompleted;
	
	public short keySize;
	boolean isPssInitaliazed = false;
	
	boolean isContainerUsed;
	
	public short certificateLabelLen;
	public byte[] certificateLabel;
	
	public KeyContainer() {
		
		userCertificate = new byte[1536];
		//evoKeyLen = 256;
		//evolutionKey = new byte[evoKeyLen];
		keySeedLength = 256;
		keySeed = new byte[keySeedLength];
		publicKeyExponent = new byte[4];
		privateKeyExponent = new byte[256];
		modulus = new byte[256];
		isContainerUsed = false;
		certificateId = new byte[64];
		certificateLabel = new byte[64];
		certificateLabelLen = 64;
		
	}

	public void initalize(byte[] inputArray, short offset, short len) {
		
		this.isCompleted = false;
		this.keySize = 0;
		
		// short size = 0;
		if (inputArray[offset] == (byte) 0xA8) {
			offset++;
			offset += Utils.getSizeBytesLen(inputArray, offset);

			// key id 0xA8 0x4A 0xB6 0x03 0x84 0x01 0x01 0x7F 0x48 0x42 0x97
			// 0x40 0x2D 0x0A 0xA0 0x19 0xBD 0xB2 0xE3

			if ((byte) inputArray[offset] == (byte) 0xB6) {
				offset++;
				offset += Utils.getSizeBytesLen(inputArray, offset);

				// key id value tag
				if ((byte) inputArray[offset] == (byte) 0x84) {
					offset++; // L
					offset += Utils.getSizeBytesLen(inputArray, offset); // V
					
					keyId = inputArray[offset];

					offset++;

					if ((byte) inputArray[offset] == (byte) 0x7F
							&& (byte) inputArray[(short) (offset + 1)] == (byte) 0x48) {

						offset += 2; // L
						offset += Utils.getSizeBytesLen(inputArray, offset); // V

						switch ((byte) inputArray[offset]) {

						case (byte) 0x97:

							offset++;
							privateKeyExponentLength = Utils.getLength(
									inputArray, offset);
							offset += Utils.getSizeBytesLen(inputArray, offset); // V

							Util.arrayCopy(inputArray, offset,
									privateKeyExponent, (short) 0,
									privateKeyExponentLength);

							break;

						case (byte) 0x98:

							offset++;

							keySeedLengthImport = Utils.getLength(inputArray, offset);

							offset += Utils.getSizeBytesLen(inputArray, offset); // V

							Util.arrayCopy(
									inputArray, 
									offset, 
									keySeed,
									(short) 0, 
									keySeedLengthImport);

							break;

						default:
							break;
						}
					} else if ((byte) inputArray[offset] == (byte) 0x7F
							&& (byte) inputArray[(short) (offset + 1)] == (byte) 0x49) {

						offset += 2; // L
						offset += Utils.getSizeBytesLen(inputArray, offset); // V

						switch ((byte) inputArray[offset]) {

						case (byte) 0x81:

							offset++;
							modulusLength = Utils.getLength(inputArray, offset);
							offset += Utils.getSizeBytesLen(inputArray, offset); // V

							Util.arrayCopy(inputArray, offset, modulus,
									(short) 0, modulusLength);
				
							break;
							
						case (byte) 0x82:

							offset++;
							publicKeyExponentLength = Utils.getLength(
									inputArray, offset);
							offset += Utils.getSizeBytesLen(inputArray, offset); // V

							Util.arrayCopy(inputArray, offset,
									publicKeyExponent, (short) 0,
									publicKeyExponentLength);

							break;

						default:
							break;
						}
					}

					if (modulusLength != 0 && publicKeyExponentLength != 0
							&& privateKeyExponentLength != 0
							&& keySeedLengthImport != 0) {
						if (modulusLength == privateKeyExponentLength) {

							this.isCompleted = true;
							this.keySize = (short) (modulusLength * 8);
							this.isContainerUsed = false;
							
							setCryptoKeys(
									privateKeyExponent, privateKeyExponentLength,
									publicKeyExponent, publicKeyExponentLength, 
									modulus, modulusLength, keySize, 
									keySeed, keySeedLengthImport);
							
							modulusLength = 0;
							publicKeyExponentLength = 0;
							privateKeyExponentLength = 0;
							keySeedLengthImport = 0;
							
						}
					}
				}
			}
		}

		// ISOException.throwIt(ISO7816.SW_WRONG_DATA);
	}
	
	private void setCryptoKeys(byte[] privateKeyExponent, short pkeLength,
			byte[] publicKeyExponent, short pubKLength, byte[] keyModulus,
			short modLength, short rsaLength, byte[] keySeed, short keySeedLen) {


		/* private key */
		privateKey = (RSAPrivateKey) KeyBuilder.buildKey(
					KeyBuilder.TYPE_RSA_PRIVATE, rsaLength, false);

			
		// ISOException.throwIt(SW_CRYPTO_EXCEPTION);
		privateKey.setExponent(privateKeyExponent, (short) 0, pkeLength);
		privateKey.setModulus(keyModulus, (short) 0, modLength);

		/* public key */
		publicKey = (RSAPublicKey) KeyBuilder.buildKey(
				KeyBuilder.TYPE_RSA_PUBLIC, rsaLength, false);
		publicKey.setExponent(publicKeyExponent, (short) 0, pubKLength);
		publicKey.setModulus(keyModulus, (short) 0, modLength);
		
		/* seed key */
		//this.keySeedLength = keySeedLen;
		Util.arrayCopy(keySeed, (short)0, this.keySeed, (short)0, keySeedLen);
		
	}

	public void setUserCertificate(byte[] userCert, short off, short len) {
		
		userCertLen = len;
		Util.arrayCopy(userCert, off, userCertificate, (short) 0, userCertLen);
	}

	public RSAPrivateKey getPrivateKey() {
		return privateKey;
	}

	public void setPrivateKey(RSAPrivateKey privateKey) {
		this.privateKey = privateKey;
	}

	public void setPrivateKey(byte[] modulus, short modOff, short modLen,
			byte[] privateExponent, short expoOff, short expoLen) {
		
		/* private key */
		
		setPrivateKey((RSAPrivateKey) KeyBuilder.buildKey(
				KeyBuilder.TYPE_RSA_PRIVATE, (short) (modLen * 8), false));
		privateKey.setExponent(privateExponent, expoOff, expoLen);
		privateKey.setModulus(modulus, modOff, modLen);
	}

	public void setPublicKey(byte[] modulus, short modOff, short modLen,
			byte[] publicExponent, short expoOff, short expoLen) {
		
		/* public key */
		publicKey = (RSAPublicKey) KeyBuilder.buildKey(
				KeyBuilder.TYPE_RSA_PUBLIC, (short) (modLen * 8), false);
		
		publicKey.setExponent(publicExponent, expoOff, expoLen);
		publicKey.setModulus(modulus, modOff, modLen);

	}
	
	public byte getKeyId() {
		return keyId;
	}

	public void setKeyId(byte keyId) {
		this.keyId = keyId;
	}
	
	public void setKeySeed(byte[] keySeed) {
		Util.arrayCopy(keySeed, (short)0, this.keySeed, (short)0, this.keySeedLength);
	}

	public void setCertificateId(byte[] inputBuffer, short inOffset, short inLen) {
		// TODO Auto-generated method stub
		certificateIdLen = inLen;
		Util.arrayCopy(inputBuffer, inOffset, certificateId, (short) 0, certificateIdLen);
	}

	public void setCertificateLabel(byte[] inputBuffer, short inOffset,
			short inLen) {
		// TODO Auto-generated method stub
		certificateLabelLen = inLen;
		Util.arrayCopy(inputBuffer, inOffset, certificateLabel, (short) 0, certificateLabelLen);
		
	}
}
